/**
 * SystemLogAspect.java
 * Created at 2017-11-16
 * Created by zhanghailin
 * Copyright (C) 2017 BROADTEXT SOFTWARE, All rights reserved.
 */
package com.broadtext.rms.log.aspect;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.broadtext.common.annotation.SystemControllerLog;
import com.broadtext.common.utils.StringUtils;
import com.broadtext.common.utils.UUIDUtils;
import com.broadtext.rms.session.LoginResult;
import com.broadtext.rms.system.model.AccessLog;
import com.broadtext.rms.system.service.IAccessLogService;

/**
 * <p>ClassName: SystemLogAspect</p>
 * <p>Description: TODO</p>
 * <p>Author: zhanghailin</p>
 * <p>Date: 2017-11-16</p>
 */
@Aspect  
@Component
public class SystemLogAspect {
    /**
     * 登录日志服务
     */
    @Autowired
    @Qualifier("accessLogService")
    private IAccessLogService accessLogService;
    
    //Controller层切点  
    @Pointcut("@annotation(com.broadtext.common.annotation.SystemControllerLog)") 
    //@Pointcut("execution(* *..action..*Action*.*(..))") 
    public void controllerAspect(){
        
    }
    

    
    /** 
     * 前置通知 用于拦截Controller层记录用户的操作 
     * 
     * @param joinPoint 切点 
     */  
    //@Before("operationAspect()")  
    public void doBefore(JoinPoint joinPoint) {  
  
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
        HttpSession session = request.getSession();
        //读取session中的用户  
        //请求的IP  
        try {  
            String username = request.getParameter("loginName");
            if(StringUtils.isBlank(username)){
                username = String.valueOf(session.getAttribute("sys.userName"));
            }
            String ip = this.getIpAddress(request);
            String description = getControllerMethodDescription(joinPoint);
            //*========控制台输出=========*//  
            System.out.println("=====前置通知开始=====");  
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            System.out.println("方法描述:" + description);  
            System.out.println("请求人:" + username);  
            System.out.println("请求IP:" + ip);  
            //*========数据库日志=========*//  
            
            
            System.out.println("=====前置通知结束=====");  
        } catch (Exception e) {  
            //记录本地异常日志  
            e.printStackTrace();
        }  
    } 
    
    /** 
     * 前置通知 用于拦截Controller层记录用户的操作 
     * 
     * @param joinPoint 切点 
     */ 
    @SuppressWarnings("unchecked")
    //@AfterReturning(pointcut = "controllerAspect()", returning = "result")  
    public void doAfter(JoinPoint joinPoint, Object result) {  
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
        HttpSession session = request.getSession();
        Map<String, String> map = (Map<String,String>)result;
        //读取session中的用户  
        //请求的IP  
        try {  
            String username = request.getParameter("loginName");
            if(StringUtils.isBlank(username)){
                username = String.valueOf(session.getAttribute("sys.userName"));
            }
            String ip = this.getIpAddress(request);
            String description = getControllerMethodDescription(joinPoint);
            //*========控制台输出=========*//  
            System.out.println("=====前置通知开始=====");  
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            System.out.println("方法描述:" + description);  
            System.out.println("请求人:" + username);  
            System.out.println("请求IP:" + ip);  
            //*========数据库日志=========*//
            AccessLog log = new AccessLog();
            log.setPkId(UUIDUtils.getUUID());
            log.setUsername(username);
            if("login".equals(description)){
                log.setModual("登录");
                log.setLogConten("登录系统");
            }else if("logout".equals(description)){
                log.setModual("退出");
                log.setLogConten("退出系统");
            }
            log.setRemoteIp(ip);
            log.setUserId(this.accessLogService.getUserIdByUsername(username));
            log.setDelFlag("0");
            log.setCreateUser(username);
            log.setCreateDate(new Date());
            if(map!=null&&LoginResult.LOGINOK.getContext().equals(map.get("msg"))){
                this.accessLogService.insertRecord(log);
            }
            if(map == null){
                this.accessLogService.insertRecord(log);
            }
            System.out.println("=====前置通知结束=====");  
        } catch (Exception e) {  
            //记录本地异常日志  
            e.printStackTrace();
        }  
    }
    
    /** 
     * 前置通知 用于拦截Controller层记录用户的操作 
     * 
     * @param joinPoint 切点 
     */ 
    @SuppressWarnings("unchecked")
    @Around("controllerAspect()")  
    public Object doAround(ProceedingJoinPoint joinPoint)  {  
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
        HttpSession session = request.getSession();
        Map<String, String> result = null;
        //读取session中的用户  
        //请求的IP  
        try {  
            String username = request.getParameter("loginName");
            if(StringUtils.isBlank(username)){
                username = String.valueOf(session.getAttribute("sys.userName"));
            }
            String ip = this.getIpAddress(request);
            String description = getControllerMethodDescription(joinPoint);
            //*========控制台输出=========*//  
            System.out.println("=====前置通知开始=====");  
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            System.out.println("方法描述:" + description);  
            System.out.println("请求人:" + username);  
            System.out.println("请求IP:" + ip);  
            //*========数据库日志=========*//
            AccessLog log = new AccessLog();
            log.setPkId(UUIDUtils.getUUID());
            log.setUsername(username);
            if("login".equals(description)){
                log.setModual("登录");
                log.setLogConten("登录系统");
            }else if("logout".equals(description)){
                log.setModual("退出");
                log.setLogConten("退出系统");
            }
            log.setRemoteIp(ip);
            log.setUserId(this.accessLogService.getUserIdByUsername(username));
            log.setDelFlag("0");
            log.setCreateUser(username);
            log.setCreateDate(new Date());
            System.out.println("=====前置通知结束,执行目标方法=====");
            result = (Map<String,String>)joinPoint.proceed();
            if(result!=null&&LoginResult.LOGINOK.getContext().equals(result.get("msg"))){
                this.accessLogService.insertRecord(log);
            }
            if(result == null){
                this.accessLogService.insertRecord(log);
            }
            System.out.println("=====后置通知结束=====");  
        } catch (Throwable e) {  
            //记录本地异常日志  
            e.printStackTrace();
        } 
        
        return result;
    } 
    
    
    
    /**
     * <p>Description: 得到客户端IP</p>
     * @param request 请求信息
     * @return ip
     * @throws Exception 异常
     */
    private String getIpAddress(HttpServletRequest request) throws Exception {
        String ipAddress; 
        ipAddress = request.getHeader("X-Forwarded-For");   
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {   
            ipAddress = request.getHeader("Proxy-Client-IP");   
        }   
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {   
            ipAddress = request.getHeader("WL-Proxy-Client-IP");   
        }   
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {   
            ipAddress = request.getRemoteAddr();   
            if ("127.0.0.1".equals(ipAddress)) {
                InetAddress inet;  
                inet = InetAddress.getLocalHost();   
                ipAddress = inet.getHostAddress();   
            }  
        }   
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割   
        if (ipAddress != null && ipAddress.indexOf(",") > 0) {
            ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));   
        }
        return ipAddress;
    }
    
    /** 
     * 获取注解中对方法的描述信息 用于Controller层注解 
     * 
     * @param joinPoint 切点 
     * @return 方法描述 
     * @throws Exception 
     */
    @SuppressWarnings("rawtypes")
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {  
    	//获取切入点所在类的类名
        String targetName = joinPoint.getTarget().getClass().getName();  
        //获取切入点方法名
        String methodName = joinPoint.getSignature().getName(); 
        //获取切入点方法参数
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);
        //获取切入点所在类的所有方法
        Method[] methods = targetClass.getMethods();  
        String description = "";  
        //遍历方法
        for (Method method : methods) {
        	//方法名相同
            if (method.getName().equals(methodName)) {  
            	//获取方法参数类
                Class[] clazzs = method.getParameterTypes();
                //参数数量相同
                if (clazzs.length == arguments.length) {  
                	//获取描述
                    description = method.getAnnotation(SystemControllerLog.class).description();  
                    break;  
                }  
            }  
        }  
        return description;  
    }  

}
